/**
 * Copyright (c) 2007, Blue Hole Software. All rights reserved.
 * Code licensed under the Apache 2.0 License:
 * http://www.apache.org/licenses/
 */
package org.bhf.providers.security.authentication;

import org.bhf.security.common.Role;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Utility class containing methods for manipulating <code>Role</code>s
 * and <code>Role</code> parameters.
 */
final class RoleUtil
{
    /**
     * Do not instantiate.
     */
    private RoleUtil() { }

    /**
     * Merges the specified <code>Role</code> parameters.
     * <code>Role</code> parameters are represented by a <code>Map</code>
     * whose keys are parameter names (<code>String</code>) and whose
     * values are parameter values (<code>String[]</code>).
     * If each <code>Map</code> is considered a Set, this method returns
     * the union of the two Sets (i.e. no duplicate keys).
     *
     * @param a the first set of <code>Role</code> parameters.
     *      Must not be <code>null</code>.
     * @param b the second set of <code>Role</code> parameters.
     *      Must not be <code>null</code>.
     * @return Merged <code>Map</code>
     * @throws IllegalArgumentException if <code>a == null</code>
     *      or if <code>b == null</code>.
     */
    public static Map<String,String[]>  mergeParameters( final Map<String,String[]> a, final Map<String,String[]> b )
    {
        if( a == null )
            throw new IllegalArgumentException( "a == null" );
        if( b == null )
            throw new IllegalArgumentException( "b == null" );
        final Map<String,String[]> merged = new HashMap<String,String[]>();

        merged.putAll( a );

        for( Map.Entry<String,String[]>  entry : b.entrySet() )
        {
            String      parameterName   = entry.getKey();
            String[]    parameterValues = entry.getValue();

            if( parameterValues == null )
                throw new IllegalArgumentException( Localize.invalidParameters() );

            String[]    mergedValues    = merged.get( parameterName );

            if( mergedValues == null )
                mergedValues = parameterValues;
            else
                mergedValues = mergeParameterValues( mergedValues, parameterValues );

            merged.put( parameterName, mergedValues );
        }

        return merged;
    }

    /**
     * Merges the specified <code>String[]</code>s.
     * If each array is considered a Set, this method returns
     * the union of the two Sets (i.e. no duplicates).
     *
     * @param a the first <code>String[]</code>.
     *      Must not be <code>null</code>.
     * @param b the second <code>String[]</code>.
     *      Must not be <code>null</code>.
     *
     * @return the union of the two <code>String[]</code>s.
     *      Will not return <code>null</code>, though may return
     *      an empty array.
     *
     * @throws IllegalArgumentException if <code>a == null</code>
     *      or if <code>b == null</code>.
     */
    public static String[]      mergeParameterValues(
                                    final String[] a,
                                    final String[] b
                                )
    {
        if( a == null )
            throw new IllegalArgumentException( "a == null" );
        if( b == null )
            throw new IllegalArgumentException( "b == null" );

        if( a.length == 0 )     // case: a is empty
            return b;
        if( b.length == 0 )     // case: b is empty
            return a;

        final Set<String> merged = new HashSet<String>();

        merged.addAll( Arrays.asList( a ) );
        merged.addAll( Arrays.asList( b ) );

        return merged.toArray( new String[ merged.size() ] );
    }

    /**
     * Returns a copy of the specified <code>Role</code> whose parameters
     * have been ordered as specified in the <code>orderParameters</code>
     * method.
     *
     * @param role the <code>Role</code> to be copied.
     *      Must not be <code>null</code>.
     *
     * @return a copy of the specified <code>Role</code> whose parameters
     *      have been ordered as specified in the <code>orderParameters</code>
     *      method.
     *
     * @throws IllegalArgumentException if <code>role == null</code>.
     */
    public static Role copyRoleOrderParameters( final Role role )
    {
        if( role == null )
            throw new IllegalArgumentException( "role == null" );

        return new Role( role.getName(), orderParameters( role.getParameters() ) );
    }

    /**
     * Orders the specified <code>Role</code> parameters by parameter name
     * and for each parameter name, by parameter value.  A <code>Map</code>
     * of <code>Role</code> parameters has keys that represent parameter
     * names (<code>String</code>) and values that represent corresponding
     * parameter values (<code>String[]</code>).
     *
     * @param parameters the parameters to order.
     *      Must not be <code>null</code>.
     *
     * @return a <code>SortedMap</code> representing the <code>Role</code>
     *      parameters where the <code>Map</code> keys are parameter names
     *      (<code>String</code>) and the <code>Map</code> values are
     *      parameter values (<code>String[]</code>).
     *
     * @throws IllegalArgumentException if <code>parameters == null</code>.
     */
    public static SortedMap<String,String[]>     orderParameters( final Map<String,String[]> parameters )
    {
        if( parameters == null )
            throw new IllegalArgumentException( "parameters == null" );

        final SortedMap<String,String[]> orderedParameters   = new TreeMap<String,String[]>();

        for( Map.Entry<String,String[]> entry : parameters.entrySet() )
        {
            Arrays.sort( entry.getValue() );

            orderedParameters.put( entry.getKey(), entry.getValue() );
        }

        return orderedParameters;
    }
}

